package com.genexususa.eo.google.connection;

import com.genexususa.eo.google.data.*;
import com.google.api.ads.adwords.axis.factory.AdWordsServices;
import com.google.api.ads.adwords.axis.v201406.cm.*;
import com.google.api.ads.adwords.lib.client.AdWordsSession;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;


public class CampaignTargetingManager {


    private static final int PAGE_SIZE = 5000;
    private String _clientId;

    public void SetClientId(String clientId) {
        this._clientId = clientId;
    }

    public String GetClientId() {
        return _clientId;
    }

    public void Finalize() {

        SessionController sc = SessionController.getInstance();
        sc.RemoveSession(_clientId);
    }


    public String AddCampaignLanguages(String xml) {

        try {

            String result = "";

            // Get the instance of service's factory
            ServiceFactory sf = ServiceFactory.getInstance();


            //GA_ResultCreateLanguage res = new GA_ResultCreateLanguage();
            GA_Result res = new GA_Result();

            Util util = new Util();

            Document doc = util.loadXMLFromString(xml);

            XPathFactory factory = XPathFactory.newInstance();
            XPath xpath = factory.newXPath();

            XPathExpression expr = xpath.compile("//GA_Language");

            Object languageNodes = expr.evaluate(doc, XPathConstants.NODESET);

            NodeList languages = (NodeList) languageNodes;

            ArrayList<GA_ResultItem> languageList = new ArrayList<GA_ResultItem>();

            if (languages.getLength() > 0) {

                for (int i = 0; i < languages.getLength(); i++) { // For all GA_Language Nodes

                    GA_ResultItem language = new GA_ResultItem();

                    Node n = languages.item(i);

                    NodeList children = n.getChildNodes();

                    Language l = new Language();

                    for (int j = 0; j < children.getLength(); j++) {

                        if (children.item(j).getNodeName().equalsIgnoreCase("CampaignId")) {
                            language.CampaignId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("SubCampaignGxId")) {
                            language.SubCampaignGxId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("CriterionGxId")) {
                            language.LanguageGxId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("LanguageId")) {
                            language.LanguageId = Long.parseLong(children.item(j).getTextContent());
                            l.setId(Long.parseLong(children.item(j).getTextContent()));
                        }

                    }

                    language.Language = l;

                    languageList.add(language);

                }

                ArrayList<GA_ResultItem> createdLanguages = new ArrayList<GA_ResultItem>();

                for (GA_ResultItem lang : languageList) {

                    GA_ResultItem created = new GA_ResultItem();

                    created.SubCampaignGxId = lang.SubCampaignGxId;
                    created.CampaignId = lang.CampaignId;
                    created.LanguageGxId = lang.LanguageGxId;

                    CampaignCriterionOperation operation = new CampaignCriterionOperation();
                    CampaignCriterion campaignCriterion = new CampaignCriterion();
                    campaignCriterion.setCampaignId(lang.CampaignId);
                    campaignCriterion.setCriterion(lang.Language);
                    operation.setOperand(campaignCriterion);
                    operation.setOperator(Operator.ADD);

                    CampaignCriterionOperation[] operations = new CampaignCriterionOperation[]{operation};

                    // Get Campaign Criterion Service
                    CampaignCriterionServiceInterface campaignCriterionService = sf.GetCampaignCriterionService(this.GetClientId());
                    try {
                        CampaignCriterionReturnValue returnValue = campaignCriterionService.mutate(operations);

                        Thread.sleep(1000);

                        created.LanguageId = returnValue.getValue(0).getCriterion().getId();

                        createdLanguages.add(created);
                    } catch (ApiException apiException) {
                        ApiError[] apiErrors = apiException.getErrors();

                        created.LanguageId = 0L;
                        created.HasError = true;


                        for (ApiError apiError : apiErrors) {
                            ErrorsStruct errors = new ErrorsStruct();

                            errors.Message = apiError.getErrorString();

                            errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

                            com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

                            err.ErrorString = apiError.getErrorString();
                            err.fieldPath = apiError.getFieldPath();
                            err.Reason = apiException.getFaultReason();
                            err.Trigger = apiError.getTrigger();
                            err.Type = apiError.getApiErrorType();

                            errors.Errors.add(err);

                            created.Errors = errors;

                            createdLanguages.add(created);


                        }
                    }

                }

                try {

                    JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                    Marshaller marshallerObj = contextObj.createMarshaller();
                    marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                    StringWriter sw = new StringWriter();

                    res.Items = createdLanguages;

                    marshallerObj.marshal(res, sw);
                    result = sw.getBuffer().toString();

                    System.out.println(result);

                } catch (Exception exc) {
                    exc.printStackTrace();
                    result = exc.getMessage();

                }

            }


            return result;

        } catch (Exception exc) {

            GA_Result res = new GA_Result();

            ArrayList<GA_ResultItem> items = new ArrayList<GA_ResultItem>();

            GA_ResultItem error = new GA_ResultItem();

            ErrorsStruct errors = new ErrorsStruct();

            errors.Message = exc.getMessage();

            errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

            com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

            StringWriter st = new StringWriter();
            exc.printStackTrace(new PrintWriter(st));

            err.UnknownError = st.toString();

            errors.Errors.add(err);

            error.Errors = errors;

            error.HasError = true;

            items.add(error);

            String result = "";

            try {

                JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                Marshaller marshallerObj = contextObj.createMarshaller();
                marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                StringWriter sw = new StringWriter();

                res.Items = items;

                marshallerObj.marshal(res, sw);
                result = sw.getBuffer().toString();
                System.out.println(result);
                return result;

            } catch (Exception ex) {
                ex.printStackTrace();
                result = ex.getMessage();
                return result;
            }
        }
    }

    public String AddCampaignDevices(String xml) {

        try {


            String result = "";

            // Get the instance of service's factory
            ServiceFactory sf = ServiceFactory.getInstance();


            //GA_ResultCreatePlatform res = new GA_ResultCreatePlatform();

            GA_Result res = new GA_Result();


            Util util = new Util();

            Document doc = util.loadXMLFromString(xml);

            XPathFactory factory = XPathFactory.newInstance();
            XPath xpath = factory.newXPath();

            XPathExpression expr = xpath.compile("//GA_Platform");

            Object platformNodes = expr.evaluate(doc, XPathConstants.NODESET);

            NodeList platforms = (NodeList) platformNodes;

            ArrayList<GA_ResultItem> platformList = new ArrayList<GA_ResultItem>();

            if (platforms.getLength() > 0) {

                for (int i = 0; i < platforms.getLength(); i++) { // For all GA_Platform Nodes

                    GA_ResultItem pf = new GA_ResultItem();

                    Node n = platforms.item(i);

                    NodeList children = n.getChildNodes();

                    Platform platform = new Platform();

                    CampaignCriterion campaignCriterion = new CampaignCriterion();

                    for (int j = 0; j < children.getLength(); j++) {

                        if (children.item(j).getNodeName().equalsIgnoreCase("CampaignId")) {
                            pf.CampaignId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("SubCampaignGxId")) {
                            pf.SubCampaignGxId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("CriterionGxId")) {
                            pf.PlatformGxId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("PlatformId")) {
                            pf.PlatformId = Long.parseLong(children.item(j).getTextContent());
                            platform.setId(Long.parseLong(children.item(j).getTextContent()));
                        }

                    }

                    pf.Platform = platform;

                    platformList.add(pf);

                }

                ArrayList<GA_ResultItem> createdPlatforms = new ArrayList<GA_ResultItem>();

                for (GA_ResultItem p : platformList) {

                    GA_ResultItem created = new GA_ResultItem();

                    created.SubCampaignGxId = p.SubCampaignGxId;
                    created.CampaignId = p.CampaignId;
                    created.PlatformGxId = p.PlatformGxId;

                    CampaignCriterionOperation operation = new CampaignCriterionOperation();
                    CampaignCriterion campaignCriterion = new CampaignCriterion();
                    campaignCriterion.setCampaignId(p.CampaignId);
                    campaignCriterion.setCriterion(p.Platform);
                    operation.setOperand(campaignCriterion);
                    operation.setOperator(Operator.ADD);

                    CampaignCriterionOperation[] operations = new CampaignCriterionOperation[]{operation};
                    // Get Campaign Criterion Service
                    CampaignCriterionServiceInterface campaignCriterionService = sf.GetCampaignCriterionService(this.GetClientId());
                    try {
                        CampaignCriterionReturnValue returnValue = campaignCriterionService.mutate(operations);

                        Thread.sleep(1000);

                        created.PlatformId = returnValue.getValue(0).getCriterion().getId();

                        createdPlatforms.add(created);
                    } catch (ApiException apiException) {
                        ApiError[] apiErrors = apiException.getErrors();

                        created.PlatformId = 0L;
                        created.HasError = true;


                        for (ApiError apiError : apiErrors) {
                            ErrorsStruct errors = new ErrorsStruct();

                            errors.Message = apiError.getErrorString();

                            errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

                            com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

                            err.ErrorString = apiError.getErrorString();
                            err.fieldPath = apiError.getFieldPath();
                            err.Reason = apiException.getFaultReason();
                            err.Trigger = apiError.getTrigger();
                            err.Type = apiError.getApiErrorType();

                            errors.Errors.add(err);

                            created.Errors = errors;

                            createdPlatforms.add(created);


                        }
                    }

                }

                try {

                    JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                    Marshaller marshallerObj = contextObj.createMarshaller();
                    marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                    StringWriter sw = new StringWriter();

                    res.Items = createdPlatforms;

                    marshallerObj.marshal(res, sw);
                    result = sw.getBuffer().toString();

                    System.out.println(result);

                } catch (Exception exc) {
                    exc.printStackTrace();
                    result = exc.getMessage();

                }

            }


            return result;

        } catch (Exception exc) {

            GA_Result res = new GA_Result();

            ArrayList<GA_ResultItem> items = new ArrayList<GA_ResultItem>();

            GA_ResultItem error = new GA_ResultItem();

            ErrorsStruct errors = new ErrorsStruct();

            errors.Message = exc.getMessage();

            errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

            com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

            StringWriter st = new StringWriter();
            exc.printStackTrace(new PrintWriter(st));

            err.UnknownError = st.toString();

            errors.Errors.add(err);

            error.Errors = errors;

            error.HasError = true;

            items.add(error);

            String result = "";

            try {

                JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                Marshaller marshallerObj = contextObj.createMarshaller();
                marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                StringWriter sw = new StringWriter();

                res.Items = items;

                marshallerObj.marshal(res, sw);
                result = sw.getBuffer().toString();
                System.out.println(result);
                return result;

            } catch (Exception ex) {
                ex.printStackTrace();
                result = ex.getMessage();
                return result;
            }
        }
    }

    public String SetBidMultiplier(String xml) {

        try {


            String result = "";

            // Get the instance of service's factory
            ServiceFactory sf = ServiceFactory.getInstance();


            //GA_ResultCreatePlatform res = new GA_ResultCreatePlatform();

            GA_Result res = new GA_Result();


            Util util = new Util();

            Document doc = util.loadXMLFromString(xml);

            XPathFactory factory = XPathFactory.newInstance();
            XPath xpath = factory.newXPath();

            XPathExpression expr = xpath.compile("//GA_Platform");

            Object platformNodes = expr.evaluate(doc, XPathConstants.NODESET);

            NodeList platforms = (NodeList) platformNodes;

            ArrayList<GA_ResultItem> platformList = new ArrayList<GA_ResultItem>();

            if (platforms.getLength() > 0) {

                for (int i = 0; i < platforms.getLength(); i++) { // For all GA_Platform Nodes

                    GA_ResultItem pf = new GA_ResultItem();

                    Node n = platforms.item(i);

                    NodeList children = n.getChildNodes();

                    Platform platform = new Platform();

                    CampaignCriterion campaignCriterion = new CampaignCriterion();

                    for (int j = 0; j < children.getLength(); j++) {

                        if (children.item(j).getNodeName().equalsIgnoreCase("CampaignId")) {
                            pf.CampaignId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("SubCampaignGxId")) {
                            pf.SubCampaignGxId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("CriterionGxId")) {
                            pf.PlatformGxId = Long.parseLong(children.item(j).getTextContent());
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("PlatformId")) {
                            pf.PlatformId = Long.parseLong(children.item(j).getTextContent());
                            platform.setId(Long.parseLong(children.item(j).getTextContent()));
                        }

                        if (children.item(j).getNodeName().equalsIgnoreCase("BidMultiplier")) {
                            campaignCriterion.setBidModifier(Double.parseDouble(children.item(j).getTextContent()));
                        }

                    }

                    pf.Platform = platform;
                    pf.CampaignCriterion = campaignCriterion;

                    platformList.add(pf);

                }

                ArrayList<GA_ResultItem> createdPlatforms = new ArrayList<GA_ResultItem>();

                SessionController sc = SessionController.getInstance();
                AdWordsSession session = sc.GetSession(this._clientId);

                //AdWordsSession adSession = new AdWordsSession.Builder().fromFile().withClientLoginToken(sc.GetClientLoginToken()).build();
                session.setClientCustomerId(this._clientId);
                AdWordsServices adWordsServices = new AdWordsServices();

                CampaignCriterionServiceInterface campaignCriterionService = adWordsServices.get(session, CampaignCriterionServiceInterface.class);

                session.setPartialFailure(false);

                for (GA_ResultItem p : platformList) {

                    GA_ResultItem created = new GA_ResultItem();

                    created.SubCampaignGxId = p.SubCampaignGxId;
                    created.CampaignId = p.CampaignId;
                    created.PlatformGxId = p.PlatformGxId;

                    CampaignCriterionOperation operation = new CampaignCriterionOperation();
                    CampaignCriterion campaignCriterion = p.CampaignCriterion;
                    campaignCriterion.setCampaignId(p.CampaignId);
                    campaignCriterion.setCriterion(p.Platform);
                    operation.setOperand(campaignCriterion);
                    operation.setOperator(Operator.SET);

                    CampaignCriterionOperation[] operations = new CampaignCriterionOperation[]{operation};
                    // Get Campaign Criterion Service
                    //campaignCriterionService = sf.GetCampaignCriterionService(this.GetClientId());
                    try {
                        CampaignCriterionReturnValue returnValue = campaignCriterionService.mutate(operations);

                        Thread.sleep(1000);

                        created.PlatformId = returnValue.getValue(0).getCriterion().getId();

                        createdPlatforms.add(created);
                    } catch (ApiException apiException) {
                        ApiError[] apiErrors = apiException.getErrors();

                        created.PlatformId = 0L;
                        created.HasError = true;


                        for (ApiError apiError : apiErrors) {
                            ErrorsStruct errors = new ErrorsStruct();

                            errors.Message = apiError.getErrorString();

                            errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

                            com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

                            err.ErrorString = apiError.getErrorString();
                            err.fieldPath = apiError.getFieldPath();
                            err.Reason = apiException.getFaultReason();
                            err.Trigger = apiError.getTrigger();
                            err.Type = apiError.getApiErrorType();

                            errors.Errors.add(err);

                            created.Errors = errors;

                            createdPlatforms.add(created);


                        }
                    }

                }

                try {

                    JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                    Marshaller marshallerObj = contextObj.createMarshaller();
                    marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                    StringWriter sw = new StringWriter();

                    res.Items = createdPlatforms;

                    marshallerObj.marshal(res, sw);
                    result = sw.getBuffer().toString();

                    System.out.println(result);

                } catch (Exception exc) {
                    exc.printStackTrace();
                    result = exc.getMessage();

                }

            }


            return result;

        } catch (Exception exc) {

            GA_Result res = new GA_Result();

            ArrayList<GA_ResultItem> items = new ArrayList<GA_ResultItem>();

            GA_ResultItem error = new GA_ResultItem();

            ErrorsStruct errors = new ErrorsStruct();

            errors.Message = exc.getMessage();

            errors.Errors = new ArrayList<com.genexususa.eo.google.data.Error>();

            com.genexususa.eo.google.data.Error err = new com.genexususa.eo.google.data.Error();

            StringWriter st = new StringWriter();
            exc.printStackTrace(new PrintWriter(st));

            err.UnknownError = st.toString();

            errors.Errors.add(err);

            error.Errors = errors;

            error.HasError = true;

            items.add(error);

            String result = "";

            try {

                JAXBContext contextObj = JAXBContext.newInstance(GA_Result.class);

                Marshaller marshallerObj = contextObj.createMarshaller();
                marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

                StringWriter sw = new StringWriter();

                res.Items = items;

                marshallerObj.marshal(res, sw);
                result = sw.getBuffer().toString();
                System.out.println(result);
                return result;

            } catch (Exception ex) {
                ex.printStackTrace();
                result = ex.getMessage();
                return result;
            }
        }
    }

    protected ArrayList<PlatformReport> GetCampaignDevices(String clientId) {

        ArrayList<PlatformReport> result = new ArrayList<PlatformReport>();


        // Get the instance of service's factory
        ServiceFactory sf = ServiceFactory.getInstance();

        try {
            // Get Campaign Criterion Service
            CampaignCriterionServiceInterface campaignCriterionService = sf.GetCampaignCriterionService(clientId);


            int offset = 0;

            // Create selector.
            Selector selector = new Selector();
            selector.setFields(new String[]{
                    "BidModifier",
                    "Id",
                    "PlatformName"
            });
            //selector.setOrdering(new OrderBy[] {new OrderBy("Name", SortOrder.ASCENDING)});
            Predicate platformPredicate = new Predicate("CriteriaType", PredicateOperator.IN, new String[]{"PLATFORM"});
            selector.setPaging(new Paging(offset, PAGE_SIZE));

            // Create predicates.
        /*Predicate campaignIdPredicate =
                new Predicate("CampaignId", PredicateOperator.IN, campaignIds);*/
            selector.setPredicates(new Predicate[]{platformPredicate});

            CampaignCriterionPage page = null;

            try {

                do {
                    page = campaignCriterionService.get(selector);

                    if (page.getEntries() != null) {

                        for (CampaignCriterion campaignCriterion : page.getEntries()) {
                            if (campaignCriterion.getCriterion() instanceof Platform) {
                                Platform platform = (Platform) campaignCriterion.getCriterion();
                                PlatformReport platformReport = new PlatformReport();

                                platformReport.BidMultiplier = campaignCriterion.getBidModifier();
                                platformReport.CampaignId = campaignCriterion.getCampaignId();
                                platformReport.Id = platform.getId();
                                platformReport.Name = platform.getPlatformName();

                                result.add(platformReport);
                            }
                        }
                    }

                    offset += PAGE_SIZE;
                    selector.getPaging().setStartIndex(offset);

                } while (offset < page.getTotalNumEntries());


            } catch (Exception exc) {
                exc.printStackTrace(System.out);
            }
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
        }

        return result;

    }

    protected ArrayList<LanguageReport> GetCampaignLanguages(String clientId) {

        ArrayList<LanguageReport> result = new ArrayList<LanguageReport>();


        // Get the instance of service's factory
        ServiceFactory sf = ServiceFactory.getInstance();

        try {
            // Get Campaign Criterion Service
            CampaignCriterionServiceInterface campaignCriterionService = sf.GetCampaignCriterionService(clientId);


            int offset = 0;

            // Create selector.
            Selector selector = new Selector();
            selector.setFields(new String[]{
                    "Id",
                    "LanguageName"
            });
            //selector.setOrdering(new OrderBy[] {new OrderBy("Name", SortOrder.ASCENDING)});
            Predicate languagePredicate = new Predicate("CriteriaType", PredicateOperator.IN, new String[]{"LANGUAGE"});

            selector.setPaging(new Paging(offset, PAGE_SIZE));

            // Create predicates.
        /*Predicate campaignIdPredicate =
                new Predicate("CampaignId", PredicateOperator.IN, campaignIds);*/
            selector.setPredicates(new Predicate[]{languagePredicate});

            CampaignCriterionPage page = null;

            try {

                do {
                    page = campaignCriterionService.get(selector);

                    if (page.getEntries() != null) {

                        for (CampaignCriterion campaignCriterion : page.getEntries()) {
                            if (campaignCriterion.getCriterion() instanceof Language) {
                                LanguageReport languageReport = new LanguageReport();
                                languageReport.CampaignId = campaignCriterion.getCampaignId();
                                languageReport.Id = ((Language) campaignCriterion.getCriterion()).getId();
                                languageReport.Name = ((Language) campaignCriterion.getCriterion()).getName();

                                result.add(languageReport);
                            }
                        }
                    }

                    offset += PAGE_SIZE;
                    selector.getPaging().setStartIndex(offset);

                } while (offset < page.getTotalNumEntries());


            } catch (Exception exc) {
                exc.printStackTrace(System.out);
            }
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
        }

        return result;

    }

}
